package net.peelmeagrape.hibernate;

import net.peelmeagrape.hibernate.xmlgen.ChildElement;
import net.peelmeagrape.hibernate.xmlgen.XmlAttribute;
import net.peelmeagrape.hibernate.xmlgen.XmlElement;

import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * Polymorphic data requires a column holding a class discriminator value. This
 * value is not directly exposed to the application.
 * Required for polymorphic persistence using the table-per-class-hierarchy
 * mapping strategy ({@link H8Subclass}) and declares a discriminator column of the table. The
 * discriminator column contains marker values that tell the persistence
 * layer what subclass to instantiate for a particular row.
 * <br/>
 * <br/>
 * Actual values of the discriminator column are specified by the {@link net.peelmeagrape.hibernate.H8Class#discriminatorValue()}
 * attribute of the {@link H8Class}, {@link H8Subclass} ({@link net.peelmeagrape.hibernate.H8Subclass#discriminatorValue()}),
 * {@link Subclass} ({@link net.peelmeagrape.hibernate.Subclass#discriminatorValue()}).
 */
@Retention(RUNTIME)
@XmlElement(name="discriminator")
public @interface Discriminator
{
    @ChildElement(1) Column[] columnMapping() default {};

    /**
     * (optional - defaults to 'class') the name of the discriminator column.
     */
    @XmlAttribute String column() default "class";

    /**
     * (optional) an arbitrary SQL expression that is executed when a type has to be evaluated.
     * Allows content-based discrimination. e.g.:
     * <pre>
        &#64;{@link Discriminator}(
            formula = "case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end",
            type="integer"
        )
     </pre>
     */
    @XmlAttribute String formula() default "";

    /**
     * (optional - defaults to string) a name that indicates the Hibernate type. A restricted set
     * of types may be used: string, character, integer, byte, short, boolean,
     * yes_no, true_false.
     */
    @XmlAttribute String type() default "string";

    @XmlAttribute("not-null") boolean notNull() default true;

    @XmlAttribute int length() default 255;

    /**
     * (optional - defaults to false) "force" Hibernate to specify allowed discriminator
     * values even when retrieving all instances of the root class.
     * The force attribute is (only) useful if the table contains rows with "extra" discriminator
     * values that are not mapped to a persistent class. This will not usually be the case.
     */
    @XmlAttribute boolean force() default false;

    /**
     * (optional - defaults to true) set this to false if your discriminator column is also part
     * of a mapped composite identifier. (Tells Hibernate to not include the column in SQL INSERTs.)
     */
    @XmlAttribute boolean insert() default true;
}
